package procilege.impl.expand;

import static java.util.logging.Level.FINEST;

import java.util.Collection;
import java.util.logging.Logger;

import procilege.compute.ExprExpandTraveller;
import procilege.compute.ExprFormatter;
import procilege.compute.PlaceTypeMetadata;
import procilege.compute.PlaceType;
import procilege.impl.NameImpl;
import procilege.lang.BoolExprElement;
import procilege.lang.EntityExprElement;
import procilege.lang.ExprElement;
import procilege.lang.PrivExprComposition;
import procilege.lang.PrivExprElement;
import procilege.lang.PrivExprMergence;

import com.google.inject.Inject;

@PlaceTypeMetadata(type = NameImpl.class)
public class NameExpandPlace implements PlaceType<ExprExpandTraveller> {
	@Inject
	private ExprFormatter ftr;

	@Inject
	private Logger logger;

	public void visit(ExprExpandTraveller tr, Object place) {

		long name = ((NameImpl) place).nameId;

		// Type inference by the neighbor of the place.
		ExprElement neighbor = tr.getNeighbor();
		if (neighbor instanceof PrivExprElement) {

			Collection<PrivExprMergence> app = tr.getApplication(name);
			if (app == null) {
				tr.result(place);
				return;
			}
			
			PrivExprComposition applied = new PrivExprComposition();
			for (PrivExprElement exp : app) {
				applied.add(exp);
			}

			if (logger.isLoggable(FINEST)) {
				logger.finest(String.format("applied, { %d /'%s'}", name, ftr
						.toString(applied)));
			}
			tr.result(applied);

			return;
		} else if (neighbor instanceof BoolExprElement
				|| neighbor instanceof EntityExprElement) {

			tr.result(place);
			return;
		} else
			throw new IllegalStateException("unkown bearer: " + neighbor);
	}
}